package mylittleinvestigations.DialogCutscenes;

import java.io.IOException;
import java.util.ArrayList;
import mylittleinvestigations.CaseInformation.Case;
import mylittleinvestigations.CaseInformation.CaseXmlReader;
import mylittleinvestigations.CaseInformation.CaseXmlWriter;
import mylittleinvestigations.EasingFunctions.EasingFunction;
import mylittleinvestigations.EasingFunctions.LinearEase;
import mylittleinvestigations.Sprite;
import mylittleinvestigations.Vector2;
import org.newdawn.slick.*;

public class DialogCutsceneAnimation
{
    private Sprite backgroundSprite;
    private ArrayList<String> elementIdList;
    private ArrayList<DialogCutsceneAnimationElement> elementList;
    private ArrayList<DialogCutsceneAnimationFrame> frameList;
    private int frameIndex;
    
    private Sprite replacementBackgroundSprite;
    private double replacementBackgroundSpriteOpacity;
    private EasingFunction replacementBackgroundSpriteOpacityEase;
    
    private String id;

    public String getId() { return this.id; }
    public void setId(String id) { this.id = id; }
    
    private int changeBackgroundCount;
    
    public int getChangeBackgroundCount() { return this.changeBackgroundCount; }
    public void incrementChangeBackgroundCount() { this.changeBackgroundCount++; }
    
    private String backgroundTextureId;

    public String getBackgroundTextureId() { return this.backgroundTextureId; }
    public void setBackgroundTextureId(String backgroundTextureId) { this.backgroundTextureId = backgroundTextureId; }

    public Sprite getBackgroundSprite()
    {
        if (this.backgroundSprite == null)
        {
            this.backgroundSprite = Case.getInstance().getSpriteManager().GetSpriteFromId(this.getBackgroundTextureId());
        }

        return this.backgroundSprite;
    }

    public ArrayList<DialogCutsceneAnimationElement> getElementList()
    {
        if (this.elementList == null)
        {
            this.elementList = new ArrayList<DialogCutsceneAnimationElement>();

            for (int i = 0; i < this.elementIdList.size(); i++)
            {
                this.elementList.add(Case.getInstance().getDialogCutsceneManager().GetElementFromId(this.elementIdList.get(i)));
            }
        }

        return this.elementList;
    }
    
    private boolean isFinished;

    public boolean getIsFinished() { return this.isFinished; }
    public void setIsFinished(boolean isFinished) { this.isFinished = isFinished; }

    public DialogCutsceneAnimation()
    {
        this.backgroundTextureId = null;
        this.elementIdList = new ArrayList<String>();
        this.frameList = new ArrayList<DialogCutsceneAnimationFrame>();
        this.changeBackgroundCount = 0;
    }

    public void AddElement(String id, DialogCutsceneAnimationElement element)
    {
        Case.getInstance().getDialogCutsceneManager().AddElement(id, element);
        this.elementIdList.add(id);
    }

    public void AddFrame(DialogCutsceneAnimationFrame frame)
    {
        this.frameList.add(frame);
    }

    public void Begin()
    {
        this.setIsFinished(false);
        this.frameIndex = -1;
        this.MoveToNextFrame();
        
        this.backgroundSprite = null;
        this.replacementBackgroundSprite = null;
        this.replacementBackgroundSpriteOpacity = 0;
        this.replacementBackgroundSpriteOpacityEase = null;
    }

    public void Update(GameContainer gc, int delta)
    {
        if (this.replacementBackgroundSprite != null)
        {
            this.replacementBackgroundSpriteOpacityEase.Update(gc, delta);
            this.replacementBackgroundSpriteOpacity = this.replacementBackgroundSpriteOpacityEase.GetCurrentValue();
            
            if (this.replacementBackgroundSpriteOpacityEase.getIsFinished())
            {
                this.backgroundSprite = this.replacementBackgroundSprite;
                this.replacementBackgroundSprite = null;
                this.replacementBackgroundSpriteOpacity = 0;
                this.replacementBackgroundSpriteOpacityEase = null;
            }
        }
        
        ArrayList<DialogCutsceneAnimationElement> elementList = this.getElementList();
        
        for (int i = 0; i < elementList.size(); i++)
        {
            elementList.get(i).Update(gc,delta);
        }
    }

    public void Draw(GameContainer gc, Graphics g)
    {
        this.getBackgroundSprite().Draw(gc, g, new Vector2(0, 0));
        
        if (this.replacementBackgroundSprite != null)
        {
            this.replacementBackgroundSprite.Draw(gc, g, new Vector2(0, 0), new Color(1.0f, 1.0f, 1.0f, (float)this.replacementBackgroundSpriteOpacity));
        }
        
        ArrayList<DialogCutsceneAnimationElement> elementList = this.getElementList();

        for (int i = 0; i < elementList.size(); i++)
        {
            elementList.get(i).Draw(gc, g);
        }
    }

    public void Reset()
    {
        ArrayList<DialogCutsceneAnimationElement> elementList = this.getElementList();
        
        for (int i = 0; i < elementList.size(); i++)
        {
            elementList.get(i).Reset();
        }
        
        this.backgroundSprite = null;
        this.replacementBackgroundSprite = null;
        this.replacementBackgroundSpriteOpacity = 0;
        this.replacementBackgroundSpriteOpacityEase = null;
    }

    public void FinishCurrentFrame()
    {
        if (this.replacementBackgroundSprite != null)
        {
            this.backgroundSprite = this.replacementBackgroundSprite;
            this.replacementBackgroundSprite = null;
            this.replacementBackgroundSpriteOpacity = 0;
            this.replacementBackgroundSpriteOpacityEase = null;
        }
        
        ArrayList<DialogCutsceneAnimationElement> elementList = this.getElementList();
        
        for (int i = 0; i < elementList.size(); i++)
        {
            elementList.get(i).Finish();
        }
    }

    public void MoveToNextFrame()
    {
        this.frameIndex++;
        
        if (this.replacementBackgroundSprite != null)
        {
            this.backgroundSprite = this.replacementBackgroundSprite;
            this.replacementBackgroundSprite = null;
            this.replacementBackgroundSpriteOpacity = 0;
            this.replacementBackgroundSpriteOpacityEase = null;
        }

        ArrayList<DialogCutsceneAnimationElement> elementList = this.getElementList();
        
        for (int i = 0; i < elementList.size(); i++)
        {
            elementList.get(i).Finish();
            elementList.get(i).ClearEasingFunctions();
        }

        if (this.frameIndex < this.frameList.size())
        {
            DialogCutsceneAnimationFrame frame = this.frameList.get(this.frameIndex);
            
            frame.Begin();
            
            if (frame.getNewBackgroundTextureId() != null)
            {
                this.replacementBackgroundSprite = Case.getInstance().getSpriteManager().GetSpriteFromId(frame.getNewBackgroundTextureId());
                this.replacementBackgroundSpriteOpacityEase = new LinearEase(0.0, 1.0, frame.getMsDuration());
                this.replacementBackgroundSpriteOpacityEase.Begin();
            }
        }
        else
        {
            this.setIsFinished(true);
        }
    }

    public void SaveToXml(CaseXmlWriter writer) throws IOException
    {
        writer.StartElement("DialogCutsceneAnimation");
        
        Case.getInstance().getSpriteManager().StartGroup("DialogCutscene" + this.id);
        
        writer.WriteTextElement("Id", this.id);
        writer.WriteSpriteId("BackgroundSpriteId", this.backgroundTextureId);
        
        writer.StartElement("ElementIdList");
        
        for (int i = 0; i < this.elementIdList.size(); i++)
        {
            writer.StartElement("Entry");
            writer.WriteTextElement("ElementId", this.elementIdList.get(i));
            writer.EndElement();
        }
        
        writer.EndElement();
        
        writer.StartElement("FrameList");
        
        for (int i = 0; i < this.frameList.size(); i++)
        {
            writer.StartElement("Entry");
            this.frameList.get(i).SaveAsXml(writer);
            writer.EndElement();
        }
        
        writer.EndElement();
        
        Case.getInstance().getSpriteManager().EndGroup();
        
        writer.EndElement();
    }

    public DialogCutsceneAnimation(CaseXmlReader reader)
    {
        this.elementIdList = new ArrayList<String>();
        this.frameList = new ArrayList<DialogCutsceneAnimationFrame>();
        
        reader.StartElement("DialogCutsceneAnimation");
        
        this.id = reader.ReadTextElement("Id");
        this.backgroundTextureId = reader.ReadTextElement("BackgroundSpriteId");
        
        reader.StartElement("ElementIdList");
        reader.StartList("Entry");
        
        while (reader.MoveToNextListItem())
        {
            this.elementIdList.add(reader.ReadTextElement("ElementId"));
        }
        
        reader.EndElement();
        
        reader.StartElement("FrameList");
        reader.StartList("Entry");
        
        while (reader.MoveToNextListItem())
        {
            this.frameList.add(new DialogCutsceneAnimationFrame(reader));
        }
        
        reader.EndElement();
        
        reader.EndElement();
    }

    public void markChildSprites(String markParent)
    {
        this.getBackgroundSprite().markChildSprites(markParent);
        
        for (DialogCutsceneAnimationElement e : getElementList())
        {
            e.markChildSprites(markParent);
        }
        
        for (DialogCutsceneAnimationFrame f : frameList)
        {
            f.markChildSprites(markParent);
        }
    }
}